package com.zishuimuyu.job.download;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.extra.ftp.Ftp;
import cn.hutool.extra.ftp.FtpConfig;
import cn.hutool.extra.ftp.FtpMode;
import cn.hutool.extra.ssh.Sftp;
import cn.hutool.setting.Setting;
import cn.hutool.setting.SettingUtil;
import com.zishuimuyu.utills.MyFileTypeUtil;
import com.zishuimuyu.utills.SaveRecordsUtil;
import lombok.extern.slf4j.Slf4j;
import org.ini4j.Ini;
import org.ini4j.Profile;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 本任务只用来下载文件
 *
 * @author：GJH
 * @date
 * @company：北京木联能软件股份有限公司
 */
@Slf4j
public class DownloadFileJob {
    private static Setting downloadSetting = SettingUtil.getFirstFound("config/downloadFile.setting");
    private static String protocol = "";
    private static String localPath = "";
    private static String localWeatherPath = "";
    private static String localPowerPath = "";
    private static String localBackPath = "";
    private static String countFilePath = "";
    private static String remotePath = "";
    private static String remoteWeatherPath = "";
    private static String remotePowerPath = "";
    private static String filePrefix = "";
    private static String fileExtension = "";
    private static String ClientId = "";
    private static boolean delete = true;
    private static boolean transToE = true;

    //静态代码块会在依赖注入后自动执行,并优先执行 下载
    static {
        protocol = downloadSetting.getStr("protocol", "sftp");
        localPath = downloadSetting.getStr("localPath");
        localWeatherPath = downloadSetting.getStr("localWeatherPath");
        localPowerPath = downloadSetting.getStr("localPowerPath");
        localBackPath = downloadSetting.getStr("localBackPath") + "/" + DateUtil.format(DateUtil.date(), "yyyyMM");
        countFilePath = downloadSetting.getStr("countFilePath");
        remotePath = downloadSetting.getStr("remotePath");
        remoteWeatherPath = downloadSetting.getStr("remoteWeatherPath");
        remotePowerPath = downloadSetting.getStr("remotePowerPath");
        filePrefix = downloadSetting.getStr("filePrefix", "*");
        fileExtension = downloadSetting.getStr("fileExtension", "*");
        ClientId = downloadSetting.getStr("ClientId", "JSGF");
        delete = downloadSetting.getBool("delete", true);
        transToE = downloadSetting.getBool("transToE", true);

    }

    /**
     * 将要执行的方法所在的类交个spring容器扫描(@Component),并且在要执行的方法上添加@PostConstruct注解或者静态代码块执行**
     *
     * @Postcontruct’在依赖注入完成后自动调用
     */

    public void download() {
        if (!downloadSetting.getBool("downloadJobEnable")) {
            log.info(DateUtil.now() + "-定时任务下载任务未启用：{}->> {}");
            return;
        }
        log.info(DateUtil.now() + "-定时任务下载任务启用");
        String host = downloadSetting.getStr("host");
        String charset = downloadSetting.getStr("Charset", "UTF-8");
        int defaultPort = "sftp".equalsIgnoreCase(protocol) ? 22 : 21;
        Integer port = downloadSetting.getInt("port", defaultPort);
        String userName = downloadSetting.getStr("userName");
        String passWord = downloadSetting.getStr("passWord");
        String ClientId = downloadSetting.getStr("ClientId");
        long sessionConnectTimeout = downloadSetting.getLong("sessionConnectTimeout", 10000L);
        long channelConnectedTimeout = downloadSetting.getLong("channelConnectedTimeout", 10000L);
        FtpConfig config = new FtpConfig(host, port, userName, passWord, CharsetUtil.charset(charset));
        config.setConnectionTimeout(sessionConnectTimeout);
        config.setSoTimeout(channelConnectedTimeout);
        //localBackPath = localBackPath + "/" + DateUtil.format(DateUtil.date(), "yyyyMM");
        String localBackPath_Weather = localBackPath + "/wddata/";
        String localBackPath_Power = localBackPath + "/newDQForecast/";
        FileUtil.mkdir(localPath);
        FileUtil.mkdir(localWeatherPath);
        FileUtil.mkdir(localPowerPath);
        FileUtil.mkdir(localBackPath_Weather);
        FileUtil.mkdir(localBackPath_Power);
        FileUtil.mkdir(countFilePath);

        List<String> weatherDownloadedList = new ArrayList<>();
        List<String> powerDownloadedList = new ArrayList<>();
        try {
            //1，从云端下载到本地备份文件件，返回下载成功的文件的名称
            if ("sftp".equalsIgnoreCase(protocol)) {
                weatherDownloadedList = sftpDownload(config, remoteWeatherPath, localBackPath_Weather + "/格式转换前", filePrefix, fileExtension, delete);
                powerDownloadedList = sftpDownload(config, remotePowerPath, localBackPath_Power + "/格式转换前", filePrefix, fileExtension, delete);
            }
            if ("ftp".equalsIgnoreCase(protocol)) {
                weatherDownloadedList = ftpDownload(config, remoteWeatherPath, localBackPath_Weather + "/格式转换前", filePrefix, fileExtension, delete);
                powerDownloadedList = ftpDownload(config, remotePowerPath, localBackPath_Power + "/格式转换前", filePrefix, fileExtension, delete);
            }
            if (CollUtil.isEmpty(weatherDownloadedList)) {
                log.info(DateUtil.now() + "-从云端下载文件失败，请检查云端文件是否正常");
                return;
            }
            if (CollUtil.isEmpty(powerDownloadedList)) {
                log.info(DateUtil.now() + "-从云端下载文件失败，请检查云端文件是否正常");
                return;
            }
            for (String fileName : weatherDownloadedList) {
                //2从备份文件夹复制文件到待发送的文件夹
                File sourceFile = FileUtil.file(localBackPath_Weather + "/格式转换前/", fileName);
                String targetFileName = fileName.replace(".txt", ".cime");
                File tartetFile = FileUtil.file(localBackPath_Weather + "/格式转换后/", targetFileName);
                if (transToE) {
                    // 2.1是否需要转换为E文本，
                    fileName = MyFileTypeUtil.transToEFileForWeatherFile(sourceFile, tartetFile);
                    log.info(DateUtil.now() + "-转换文本为E文本：{}->> {}", sourceFile.getPath(), tartetFile.getPath());
                    sourceFile = tartetFile;
                }
                //2.2再从备份复制到本地目录（待传输）
                FileUtil.copy(sourceFile, FileUtil.file(localWeatherPath, sourceFile.getName()), true);
                log.info(DateUtil.now() + "-复制备份文件：{}->> {}", sourceFile.getPath(), localWeatherPath + "/" + sourceFile.getName());
            }
            for (String fileName : powerDownloadedList) {
                //3从备份文件夹复制文件到待发送的文件夹
                File sourceFile = FileUtil.file(localBackPath_Power + "/格式转换前/", fileName);
                String targetFileName = fileName.replace(".txt", ".cime");
                File tartetFile = FileUtil.file(localBackPath_Power + "/格式转换后/", targetFileName);
                //3.1判断文本是否需要转换
                if (transToE) {
                    fileName = MyFileTypeUtil.transToEFileForPowerFile(sourceFile, tartetFile);
                    log.info(DateUtil.now() + "-转换文本为E文本：{}->> {}", sourceFile.getPath(), tartetFile.getPath());
                    sourceFile = tartetFile;
                }
                //3.2再从备份复制到本地目录（待传输）
                FileUtil.copy(sourceFile, FileUtil.file(localPowerPath, sourceFile.getName()), true);
                log.info(DateUtil.now() + "-复制备份文件：{}->> {}", sourceFile.getPath(), localWeatherPath + "/" + sourceFile.getName());
            }
        } catch (IOException e) {
            log.error(e.getMessage());
            e.printStackTrace();
        }

    }


    /**
     * sftp下载
     *
     * @param config            配置类
     * @param remotePath        服务端路径
     * @param localPath         本地路径(接收端)
     * @param fileNamePrefix    文件名前缀
     * @param fileNameExtension 文件名后缀
     * @param isDelete          下载成功后是否删除
     * @return java.util.List<java.lang.String>
     */
    public static List<String> sftpDownload(FtpConfig config, String remotePath, String localPath, String fileNamePrefix, String fileNameExtension, boolean isDelete) throws IOException {
        Sftp sftp = new Sftp(config);
        // try {
        //     log.info(DateUtil.now()+"-sftp服务版本：" + sftp.getClient().getServerVersion());
        //
        // } catch (SftpException e) {
        //     e.printStackTrace();
        // }
        //获取远端服务器上的文件名称
        List<String> fileNames = sftp.ls(remotePath);
        if (!"*".equals(fileNamePrefix)) {
            //根据filePrefix 前缀过滤
            fileNames = fileNames.stream().filter(fileName -> fileName.startsWith(fileNamePrefix)).collect(Collectors.toList());
        }
        if (!"*".equals(fileNameExtension)) {
            //根据fileExtension 后缀过滤
            fileNames = fileNames.stream().filter(fileName -> fileName.endsWith(fileNameExtension)).collect(Collectors.toList());
        }
        if (CollUtil.isEmpty(fileNames)) {
            IoUtil.close(sftp);
            return fileNames;
        }
        //避免重复下载（远端服务器文件未及时删除，会重复下载），先查看已经下载过的文件
        Set<String> downloadedFileNames = new HashSet<>();
        Collection<String> nodownloadedFileNames = new ArrayList<>();
        String iniFileName = "downloadedFileNames.ini";
        File iniFile = FileUtil.file(countFilePath, iniFileName);
        FileUtil.touch(iniFile);
        //加载文件
        Ini ini = new Ini(iniFile);
        //获取已经下载的
        Set<Map.Entry<String, Profile.Section>> entries = ini.entrySet();
        for (Map.Entry<String, Profile.Section> entry : entries) {
            downloadedFileNames.addAll(ini.get(entry.getKey()).keySet());
        }
        //筛选出没有下载的文件名，筛选出fileNames中，没有在downloadedFileNames中的，也就是未下载的
        nodownloadedFileNames = CollUtil.subtract(fileNames, downloadedFileNames);
        //nodownloadedFileNames = fileNames.stream().filter(fileName -> !downloadedFileNames.contains(fileName)).collect(Collectors.toList());

        List<String> downLoadFileNames = new ArrayList<>();
        for (String fileName : nodownloadedFileNames) {
            //先下载
            sftp.download(remotePath + "/" + fileName, FileUtil.file(localPath, fileName));
            log.info(DateUtil.now() + "-定时任务SFTP下载成功：{}-> {}", remotePath + "/" + fileName, localPath + "/" + fileName);
            downLoadFileNames.add(fileName);
            //下载后是否删除 isDelete
            if (isDelete) {
                sftp.delFile(remotePath + "/" + fileName);
                log.info(DateUtil.now() + "-定时任务SFTP删除远端文件：" + remotePath + "/" + fileName);
            }

        }
        IoUtil.close(sftp);
        //保存下载记录
        SaveRecordsUtil.saveDownloadLog(iniFile, downLoadFileNames);
        return downLoadFileNames;
    }

    /**
     * ftp下载
     *
     * @param config            配置类
     * @param remotePath        服务端路径
     * @param localPath         本地路径(接收端)
     * @param fileNamePrefix    文件名前缀
     * @param fileNameExtension 文件名后缀
     * @param isDelete          下载成功后是否删除
     * @return java.util.List<java.lang.String>
     */
    public static List<String> ftpDownload(FtpConfig config, String remotePath, String localPath, String fileNamePrefix, String fileNameExtension, boolean isDelete) throws IOException {
        Ftp ftp = new Ftp(config, FtpMode.Passive);
        ftp.lsFiles(remotePath);
        List<String> fileNames = ftp.ls(remotePath);
        if (!"*".equals(fileNamePrefix)) {
            //fileNamePrefix 前缀过滤
            fileNames = fileNames.stream().filter(fileName -> fileName.startsWith(fileNamePrefix)).collect(Collectors.toList());
        }
        if (!"*".equals(fileNameExtension)) {
            //根据fileExtension 后缀过滤
            fileNames = fileNames.stream().filter(fileName -> fileName.endsWith(fileNameExtension)).collect(Collectors.toList());
        }
        if (CollUtil.isEmpty(fileNames)) {
            IoUtil.close(ftp);
            return fileNames;
        }
        //避免重复下载（远端服务器文件未及时删除，会重复下载），先查看已经下载过的文件

        String iniFileName = "downloadedFileNames.ini";
        File iniFile = FileUtil.file(countFilePath, iniFileName);
        FileUtil.touch(iniFile);
        //未下载的文件名集合
        Set<String> downloadedFileNames = new HashSet<>();
        Collection<String> nodownloadedFileNames = new ArrayList<>();
        Ini ini = new Ini(iniFile);
        Set<Map.Entry<String, Profile.Section>> entries = ini.entrySet();
        for (Map.Entry<String, Profile.Section> entry : entries) {
            downloadedFileNames.addAll(ini.get(entry.getKey()).keySet());
        }
        //筛选出没有下载的文件名，筛选出fileNames中，没有在downloadedFileNames中的，也就是未下载的
        nodownloadedFileNames = CollUtil.subtract(fileNames, downloadedFileNames);
        //nodownloadedFileNames = fileNames.stream().filter(fileName -> !downloadedFileNames.contains(fileName)).collect(Collectors.toList());

        ArrayList<String> downLoadFileNames = new ArrayList<>();
        for (String fileName : nodownloadedFileNames) {
            //先下载到备份补录
            ftp.download(remotePath + "/" + fileName, FileUtil.file(localPath, fileName));
            log.info(DateUtil.now() + "-定时任务FTP下载成功：{}-> {}", remotePath + "/" + fileName, localPath + "/" + fileName);
            //再从备份复制到本地目录
            downLoadFileNames.add(fileName);
            if (isDelete) {
                ftp.delFile(remotePath + "/" + fileName);
                log.info(DateUtil.now() + "-定时任务FTP删除远端文件：" + remotePath + "/" + fileName);
            }
        }
        IoUtil.close(ftp);
        //保存下载记录
        SaveRecordsUtil.saveDownloadLog(iniFile, downLoadFileNames);
        return downLoadFileNames;
    }

}
